
#include "ttg/all.h"

using namespace ttg;
using namespace ttg::pipeline;

//Represents complex number as re + im * i.
struct Complex
{
	double re, im;

	Complex(double re, double im)
	{
		this->re = re;
		this->im = im;
	}
};

//Represents complex number as rho * (cos(phi) + i * sin(phi)).
struct PolarComplex
{
	double rho, phi;

	PolarComplex(double rho, double phi)
	{
		this->rho = rho;
		this->phi = phi;
	}
};

//Converts incoming complex numbers to polar complex numbers.
class ComplexToPolar :public Node<Complex, PolarComplex>
{
	virtual void process(Complex data)
	{
		//Converting to polar coordinate system.
		double rho = sqrt(data.re * data.re + data.im * data.im);
		double phi = math::isZeroEps(rho, 0.0001)
					? 0.0 : acos(data.re / rho) * math::getSign(asin(data.im / rho));
		//Sending result to next nodes.
		sendNext(PolarComplex(rho, phi));
	}
};

//Finds roots from incoming polar complex number.
class RootFinder :public Node<PolarComplex, PolarComplex>
{
	virtual void process(PolarComplex data)
	{
		//Calculating roots.
		PolarComplex root1(sqrt(data.rho), data.phi / 2.0);
		PolarComplex root2(sqrt(data.rho), data.phi / 2.0 + TTG_PI);
		//Sending roots to next nodes.
		sendNext(root1);
		sendNext(root2);
	}
};

//Converts incoming polar complex numbers to complex number.
class PolarToComplex :public Node<PolarComplex, Complex>
{
	virtual void process(PolarComplex data)
	{
		//Converting.
		double im = data.rho * sin(data.phi);
		double re = data.rho * cos(data.phi);
		//Sending result to next nodes.
		sendNext(Complex(re, im));
	}
};

int main()
{
	services::ServiceBase::getRef()->start();
	//Creating pipeline.
	Pipeline<Complex, Complex> pl(wrap(new ComplexToPolar()) + wrap(new RootFinder()) + wrap(new PolarToComplex()));
	//Launching pipeline and checking first root.
	Complex root = pl.run(Complex(0.0, 1.0))[0];
	if (!math::isZeroEps(root.re * root.re - root.im * root.im, 0.001) ||
		!math::isEqualEps(2 * root.re * root.im, 1.0, 0.001))
		printf("Wrong results!\n");
	else
		printf("It works!\n");
	exit(0);
}
